package app.auto.runner.base.utility.base;

import android.app.Activity;
import android.content.Context;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import app.auto.runner.base.utility.ShareAlert;
import app.auto.runner.base.utility.StorageUtil;


/**
 * ClazzUtils
 *
 * @author ZENG.XIAO.YAN
 * @version 1.0
 */

public class ClazzUtils {

    private static final String CLASS_SUFFIX = ".class";

    private static final String CLASS_FILE_PREFIX = File.separator + "classes" + File.separator;

    private static final String PACKAGE_SEPARATOR = ".";


    /**
     * 查找包下的所有类的名字
     *
     * @param packageName
     * @param showChildPackageFlag 是否需要显示子包内容
     * @return List集合，内容为类的全名
     */

    public void loadJar(String path) {
        // 系统类库路径
        File libPath = new File(path);

        // 获取所有的.jar和.zip文件
        File[] jarFiles = libPath.listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".jar") || name.endsWith(".zip");
            }
        });

        File file = null;
        loadJar(file);
    }

    void loadJar(File file) {
        // 从URLClassLoader类中获取类所在文件夹的方法
        // 对于jar文件，可以理解为一个存放class文件的文件夹
        Method method = null;
        try {
            method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        } catch (NoSuchMethodException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (SecurityException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        boolean accessible = method.isAccessible();     // 获取方法的访问权限
        try {
            if (accessible == false) {
                method.setAccessible(true);     // 设置方法的访问权限
            }
            // 获取系统类加载器
            URLClassLoader classLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();

//                for (File file : jarFiles) {
            try {
                URL url = file.toURI().toURL();
                method.invoke(classLoader, url);
                System.out.println("读取jar文件成功" + file.getName());
            } catch (Exception e) {
                System.out.println("读取jar文件失败");
            }
//                }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            method.setAccessible(accessible);
        }
    }


    public static List<String> getClazzName(String packageName, boolean showChildPackageFlag) {

        List<String> result = new ArrayList<>();

        String suffixPath = packageName.replaceAll("\\.", "/");

        ClassLoader loader = Thread.currentThread().getContextClassLoader();

        try {

            Enumeration<URL> urls = loader.getResources(suffixPath);

            while (urls.hasMoreElements()) {

                URL url = urls.nextElement();

                if (url != null) {

                    String protocol = url.getProtocol();

                    if ("file".equals(protocol)) {

                        String path = url.getPath();

                        System.out.println(path);

                        result.addAll(getAllClassNameByFile(new File(path), showChildPackageFlag));

                    } else if ("jar".equals(protocol)) {

                        JarFile jarFile = null;

                        try {

                            jarFile = ((JarURLConnection) url.openConnection()).getJarFile();

                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                        if (jarFile != null) {

                            result.addAll(getAllClassNameByJar(jarFile, packageName, showChildPackageFlag));

                        }

                    }

                }

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

        return result;

    }


    /**
     * 递归获取所有class文件的名字
     *
     * @param file
     * @param flag 是否需要迭代遍历
     * @return List
     */

    private static List<String> getAllClassNameByFile(File file, boolean flag) {

        List<String> result = new ArrayList<>();

        if (!file.exists()) {

            return result;

        }

        if (file.isFile()) {

            String path = file.getPath();

            // 注意：这里替换文件分割符要用replace。因为replaceAll里面的参数是正则表达式,而windows环境中File.separator="\\"的,因此会有问题

            if (path.endsWith(CLASS_SUFFIX)) {

                path = path.replace(CLASS_SUFFIX, "");

                // 从"/classes/"后面开始截取

                String clazzName = path.substring(path.indexOf(CLASS_FILE_PREFIX) + CLASS_FILE_PREFIX.length())

                        .replace(File.separator, PACKAGE_SEPARATOR);

                if (-1 == clazzName.indexOf("$")) {

                    result.add(clazzName);

                }

            }

            return result;


        } else {

            File[] listFiles = file.listFiles();

            if (listFiles != null && listFiles.length > 0) {

                for (File f : listFiles) {

                    if (flag) {

                        result.addAll(getAllClassNameByFile(f, flag));

                    } else {

                        if (f.isFile()) {

                            String path = f.getPath();

                            if (path.endsWith(CLASS_SUFFIX)) {

                                path = path.replace(CLASS_SUFFIX, "");

                                // 从"/classes/"后面开始截取

                                String clazzName = path.substring(path.indexOf(CLASS_FILE_PREFIX) + CLASS_FILE_PREFIX.length())

                                        .replace(File.separator, PACKAGE_SEPARATOR);

                                if (-1 == clazzName.indexOf("$")) {

                                    result.add(clazzName);

                                }

                            }

                        }

                    }

                }

            }

            return result;

        }

    }


    /**
     * 递归获取jar所有class文件的名字
     *
     * @param jarFile
     * @param packageName 包名
     * @param flag        是否需要迭代遍历
     * @return List
     */

    private static List<String> getAllClassNameByJar(JarFile jarFile, String packageName, boolean flag) {

        List<String> result = new ArrayList<>();

        Enumeration<JarEntry> entries = jarFile.entries();

        while (entries.hasMoreElements()) {

            JarEntry jarEntry = entries.nextElement();

            String name = jarEntry.getName();

            // 判断是不是class文件

            if (name.endsWith(CLASS_SUFFIX)) {

                name = name.replace(CLASS_SUFFIX, "").replace("/", ".");

                if (flag) {

                    // 如果要子包的文件,那么就只要开头相同且不是内部类就ok

                    if (name.startsWith(packageName) && -1 == name.indexOf("$")) {

                        result.add(name);

                    }

                } else {

                    // 如果不要子包的文件,那么就必须保证最后一个"."之前的字符串和包名一样且不是内部类

                    if (packageName.equals(name.substring(0, name.lastIndexOf("."))) && -1 == name.indexOf("$")) {

                        result.add(name);

                    }

                }

            }

        }

        return result;

    }


    public void pop(Context ctx) {
        File file = AssetCopyer.copyFilesFromAssets(ctx, "jar", StorageUtil.getPrimaryStoragePath(ctx));

        List<String> list = ClazzUtils.getClazzName("android.app", true);
        String ls = "";
        for (String string : list) {

            ls += string + "\n";

        }
        ShareAlert.shareAlert((Activity) ctx, ls);

    }

}